#include "network_controller.h"


NetworkController::NetworkType NetworkController::Type()
{
    return mType;
}

NetworkController::NetworkController(NetworkController::NetworkType type,
    QString ip,
    uint16_t port):
    mTcp(nullptr),
    mUDP(nullptr),
    mTcpServer(nullptr),
    mCnn(nullptr),
    mState(false)
{
    mType = type;
    if(_checkType(type) == TYPE_UNKOWN){
    }
    if(type == NetworkType::TYPE_TCP_CLIENT){
        mTcp = new QTcpSocket();
        mCnn = mTcp;

        QObject::connect(mTcp, SIGNAL(connected()), this, SLOT(on_conected()));
        QObject::connect(mTcp, SIGNAL(readyRead()), this, SLOT(on_ready_read()));
        QObject::connect(mTcp, SIGNAL(disconnected()), this, SLOT(on_disconect()));
        QObject::connect(mTcp, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
                         this, SLOT(tcpsock_stateChanged(QAbstractSocket::SocketState)));


        mTcp->connectToHost(ip,port,QIODevice::ReadWrite,QAbstractSocket::IPv4Protocol);
        qDebug()<<mTcp->state();

        if(mTcp->state() == QAbstractSocket::ConnectedState)
            mState = true;
    }

    if(type == NetworkType::TYPE_TCP_SERVER){
        qDebug()<<"tcp server mode";
        mTcpServer = new QTcpServer();
        connect(mTcpServer,SIGNAL(newConnection()),
                this,SLOT(on_server_accept()));
        connect(mTcpServer, SIGNAL(acceptError(QAbstractSocket::SocketError )),
                this, SLOT( on_accept_error(QAbstractSocket::SocketError )));

        if (!mTcpServer->listen(QHostAddress::Any, port))
        {
            qDebug() << "m_pTcpServer->listen() error";
        }
    }
    if((type == NetworkType::TYPE_UDP_SERVER) || (type == NetworkType::TYPE_UDP_CLIENT)){
        mUDP = new QUdpSocket(this);
        mUDP->bind(QHostAddress::Any, port);
        mCnn = mUDP;
        connect(mUDP, SIGNAL(readyRead()),
                this, SLOT(on_ready_read()));
        mUDP->open(QIODevice::ReadWrite);
        mState = true;
    }

}

int NetworkController::SendData(int8_t *data, uint32_t len)
{
    if(nullptr == data)
        return -1;
    return mCnn->write((const char *)data,len);
}

NetworkController::RecvResult NetworkController::ReadData(int8_t *data)
{
    RecvResult ret;
    if(nullptr == data){
        ret.len = -1;
        return ret;
    }
    if((mType == TYPE_UDP_CLIENT )||(mType == TYPE_UDP_SERVER)){
        int len = 0;
        if(mUDP->hasPendingDatagrams()){
            QNetworkDatagram datagram = mUDP->receiveDatagram();
            memcpy(data,datagram.data().data(),datagram.data().size());
            len += datagram.data().size();
            ret.addr = datagram.senderAddress().toString();
            ret.port = datagram.senderPort();
            ret.len  = datagram.data().length();
        }
    }
    else{
        auto reads = mCnn->readAll();
        memcpy(data,reads.data(),reads.size());
        ret.len = reads.size();
    }
    return ret;
}

int NetworkController::Close()
{
    if(mType == TYPE_TCP_SERVER){
        mTcpServer->close();
        if(nullptr != mCnn)
            mCnn->close();
        delete mTcpServer;
        mTcpServer = nullptr;
        mCnn = nullptr;
        mTcp = nullptr;
    }
    if(mType == TYPE_TCP_CLIENT){
        qDebug()<<(((QTcpSocket*)mTcp)->state());
        qDebug()<<"disconnected"<<mTcp->bytesAvailable()<<mCnn->bytesToWrite();
        ((QTcpSocket*)mTcp)->disconnectFromHost();
        if(((QTcpSocket*)mTcp)->waitForDisconnected(3000));
        mTcp->close();
        delete mTcp;
        mTcp = nullptr;
    }
    mState = false;
    return 0;
}

NetworkController::~NetworkController()
{
    if(mState){
        if(mTcp != nullptr)
            delete  mTcp;
        if((mCnn != nullptr) && (this->mType != NetworkType::TYPE_TCP_CLIENT))
            delete  mCnn;
        if(mTcpServer != nullptr)
            delete mTcpServer;
        if(mUDP != nullptr)
            delete  mUDP;
    }
}


bool NetworkController::State()
{
    return this->mState;
}

void NetworkController::on_conected()
{
    mState = true;
    emit(on_connected());
}

void NetworkController::tcpsock_stateChanged(QAbstractSocket::SocketState state)
{
    qDebug()<<state;
    if(state == QAbstractSocket::SocketState::UnconnectedState){
        emit(on_disconnectd());
    }
}

void NetworkController::on_ready_read()
{
    emit(on_data_recv());
}

void NetworkController::on_disconect()
{
    qDebug()<<"close";
    if(nullptr != mCnn){
        mCnn->close();
        emit(this->on_conection_close());
    }
//    if(mType == TYPE_TCP_SERVER){
//        mTcpServer->resumeAccepting();
//    }
}

void NetworkController::on_server_accept()
{
    if(mType == TYPE_TCP_SERVER){
        QTcpSocket* pClientConnection = mTcpServer->nextPendingConnection();
        if(nullptr != pClientConnection){
            QObject::connect(pClientConnection, SIGNAL(readyRead()), this, SLOT(on_ready_read()));
            QObject::connect(pClientConnection, SIGNAL(disconnected()), this, SLOT(on_disconect()));
        }
        qDebug()<<pClientConnection->socketDescriptor();
//        mTcp = pClientConnection;
//        mCnn = mTcp;
        mState = true;
        emit(on_connected());
    }
}

void NetworkController::on_accept_error(QAbstractSocket::SocketError socketError)
{
    qDebug()<<socketError;
}

NetworkController::NetworkType NetworkController::_checkType(NetworkType type){
    if(type < TYPE_UNKOWN){
        return type;
    }else{
        return TYPE_UNKOWN;
    }
}

